home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / v10n05.arc / TINYDOSX.ASM < prev    next >
Assembly Source File  |  1991-02-13  |  27KB  |  546 lines

  1.  
  2.         title   TINYDOSX DPMI-Based Tiny DOS Extender
  3.         page    55,132
  4.  
  5. ; TINYDOSX.ASM  Tiny DPMI-Based DOS Extender
  6. ; Copyright (C) 1990 Ziff Davis Communications
  7. ; PC Magazine * Ray Duncan
  8.  
  9. stdin   equ     0                       ; standard input handle
  10. stdout  equ     1                       ; standard output handle
  11. stderr  equ     2                       ; standard error handle
  12. cr      equ     0dh                     ; ASCII carriage return
  13. lf      equ     0ah                     ; ASCII line feed
  14.  
  15. DGROUP  group   _DATA
  16.  
  17. _DATA   segment word public 'DATA'
  18.  
  19. modesw  dd      0                       ; far pointer to DPMI mode 
  20.                                         ;   switch entry point
  21. int0dv  dd      0                       ; address of previous 
  22.                                         ;   GP fault handler
  23. int21v  dd      0                       ; address of previous
  24.                                         ;   Int 21H handler
  25. realseg dw      0                       ; segment of real mode buffer
  26. realsel dw      0                       ; selector for real mode buffer
  27.  
  28. gpfmsg  db      cr,lf,lf
  29.         db      'TINYDOSX: general protection fault!'
  30.         db      cr,lf
  31. gpfmsg_len equ  $-gpfmsg
  32.  
  33. abmsg   db      cr,lf,lf   
  34.         db      'TINYDOSX: unsupported DOS function!'
  35.         db      cr,lf
  36. abmsg_len equ   $-abmsg
  37.  
  38. regs    label   word                    ; real mode register structure 
  39.                                         ; for DPMI translation services
  40. regDI   label   word                    ; 00H DI or EDI
  41. regEDI  dd      0
  42. regSI   label   word                    ; 04H SI or ESI
  43. regESI  dd      0
  44. regBP   label   word                    ; 08H BP or EBP
  45. regEBP  dd      0
  46.         dd      0                       ; 0CH (reserved)
  47. regBX   label   word                    ; 10H BX or EBX
  48. regEBX  dd      0
  49. regDX   label   word                    ; 14H DX or EDX
  50. regEDX  dd      0
  51. regCX   label   word                    ; 18H CX or ECX
  52. regECX  dd      0
  53. regAX   label   word                    ; 1CH AX or EAX
  54. regEAX  dd      0
  55. cpuFLAGS dw     0                       ; 20H cpu status flags
  56. regES   dw      0                       ; 22H ES
  57. regDS   dw      0                       ; 24H DS
  58. regFS   dw      0                       ; 26H FS
  59. regGS   dw      0                       ; 28H GS
  60. regIP   dw      0                       ; 2AH IP (CS:IP ignored by
  61. regCS   dw      0                       ; 2CH CS  DPMI function 0300H)
  62. regSP   dw      0                       ; 2EH SP (SS:SP=0 to have DPMI
  63. regSS   dw      0                       ; 30H SS  host supply a stack)
  64.  
  65. protDX  dw      0                       ; save protected mode DX
  66. protSI  dw      0                       ; save protected mode SI
  67. protES  dw      0                       ; save protected mode ES
  68.  
  69. dispatch label  word                    ; Int 21H dispatch table
  70.         dw      offset _TEXT:fxn00h     ; fxn 00H terminate
  71.         dw      offset _TEXT:fxn01h     ; fxn 01H char input+echo
  72.         dw      offset _TEXT:fxn02h     ; fxn 02H char output
  73.         dw      offset _TEXT:fxn03h     ; fxn 03H aux input
  74.         dw      offset _TEXT:fxn04h     ; fxn 04H aux output
  75.         dw      offset _TEXT:fxn05h     ; fxn 05H printer output
  76.         dw      offset _TEXT:fxn06h     ; fxn 06H raw console I/O
  77.         dw      offset _TEXT:fxn07h     ; fxn 07H raw input no echo
  78.         dw      offset _TEXT:fxn08h     ; fxn 08H char input no echo
  79.         dw      offset _TEXT:abort      ; fxn 09H
  80.         dw      offset _TEXT:abort      ; fxn 0AH
  81.         dw      offset _TEXT:fxn0bh     ; fxn 0BH input status
  82.         dw      offset _TEXT:abort      ; fxn 0CH
  83.         dw      offset _TEXT:fxn0dh     ; fxn 0DH disk reset
  84.         dw      offset _TEXT:fxn0eh     ; fxn 0EH select disk
  85.         dw      offset _TEXT:abort      ; fxn 0FH 
  86.         dw      offset _TEXT:abort      ; fxn 10H
  87.         dw      offset _TEXT:abort      ; fxn 11H
  88.         dw      offset _TEXT:abort      ; fxn 12H
  89.         dw      offset _TEXT:abort      ; fxn 13H
  90.         dw      offset _TEXT:abort      ; fxn 14H
  91.         dw      offset _TEXT:abort      ; fxn 15H
  92.         dw      offset _TEXT:abort      ; fxn 16H
  93.         dw      offset _TEXT:abort      ; fxn 17H
  94.         dw      offset _TEXT:abort      ; fxn 18H
  95.         dw      offset _TEXT:fxn19h     ; fxn 19H get current drive
  96.         dw      offset _TEXT:abort      ; fxn 1AH
  97.         dw      offset _TEXT:fxn1bh     ; fxn 1BH get cur. drive data
  98.         dw      offset _TEXT:fxn1ch     ; fxn 1CH get drive data
  99.         dw      offset _TEXT:abort      ; fxn 1DH
  100.         dw      offset _TEXT:abort      ; fxn 1EH
  101.         dw      offset _TEXT:abort      ; fxn 1FH 
  102.         dw      offset _TEXT:abort      ; fxn 20H
  103.         dw      offset _TEXT:abort      ; fxn 21H
  104.         dw      offset _TEXT:abort      ; fxn 22H
  105.         dw      offset _TEXT:abort      ; fxn 23H
  106.         dw      offset _TEXT:abort      ; fxn 24H
  107.         dw      offset _TEXT:abort      ; fxn 25H
  108.         dw      offset _TEXT:abort      ; fxn 26H
  109.         dw      offset _TEXT:abort      ; fxn 27H
  110.         dw      offset _TEXT:abort      ; fxn 28H
  111.         dw      offset _TEXT:abort      ; fxn 29H
  112.         dw      offset _TEXT:fxn2ah     ; fxn 2AH get date
  113.         dw      offset _TEXT:fxn2bh     ; fxn 2BH set date
  114.         dw      offset _TEXT:fxn2ch     ; fxn 2CH get time
  115.         dw      offset _TEXT:fxn2dh     ; fxn 2DH set time
  116.         dw      offset _TEXT:fxn2eh     ; fxn 2EH set verify flag
  117.         dw      offset _TEXT:abort      ; fxn 2FH
  118.         dw      offset _TEXT:fxn30h     ; fxn 30H get DOS version
  119.         dw      offset _TEXT:abort      ; fxn 31H
  120.         dw      offset _TEXT:abort      ; fxn 32H
  121.         dw      offset _TEXT:fxn33h     ; fxn 33H get/set break flag
  122.         dw      offset _TEXT:abort      ; fxn 34H
  123.         dw      offset _TEXT:abort      ; fxn 35H
  124.         dw      offset _TEXT:fxn36h     ; fxn 36H get drive info
  125.         dw      offset _TEXT:abort      ; fxn 37H
  126.         dw      offset _TEXT:error      ; fxn 38H
  127.         dw      offset _TEXT:fxn39h     ; fxn 39H create directory
  128.         dw      offset _TEXT:fxn3ah     ; fxn 3AH delete directory
  129.         dw      offset _TEXT:fxn3bh     ; fxn 3BH select directory
  130.         dw      offset _TEXT:fxn3ch     ; fxn 3CH create file
  131.         dw      offset _TEXT:fxn3dh     ; fxn 3DH open file
  132.         dw      offset _TEXT:fxn3eh     ; fxn 3EH close file
  133.         dw      offset _TEXT:fxn3fh     ; fxn 3FH read file
  134.         dw      offset _TEXT:fxn40h     ; fxn 40H write file
  135.         dw      offset _TEXT:fxn41h     ; fxn 41H delete file
  136.         dw      offset _TEXT:fxn42h     ; fxn 42H seek 
  137.         dw      offset _TEXT:fxn43h     ; fxn 43H get/set attributes
  138.         dw      offset _TEXT:error      ; fxn 44H
  139.         dw      offset _TEXT:fxn45h     ; fxn 45H dup handle
  140.         dw      offset _TEXT:fxn46h     ; fxn 46H redirect handle
  141.         dw      offset _TEXT:fxn47h     ; fxn 47H get cur. directory
  142.         dw      offset _TEXT:error      ; fxn 48H
  143.         dw      offset _TEXT:error      ; fxn 49H
  144.         dw      offset _TEXT:error      ; fxn 4AH
  145.         dw      offset _TEXT:error      ; fxn 4BH
  146.         dw      offset _TEXT:fxn4ch     ; fxn 4CH terminate
  147.         dw      offset _TEXT:abort      ; fxn 4DH
  148.         dw      offset _TEXT:error      ; fxn 4EH
  149.         dw      offset _TEXT:error      ; fxn 4FH
  150.         dw      offset _TEXT:abort      ; fxn 50H
  151.         dw      offset _TEXT:abort      ; fxn 51H
  152.         dw      offset _TEXT:abort      ; fxn 52H
  153.         dw      offset _TEXT:abort      ; fxn 53H
  154.         dw      offset _TEXT:fxn54h     ; fxn 54H get verify flag
  155.         dw      offset _TEXT:abort      ; fxn 55H
  156.         dw      offset _TEXT:error      ; fxn 56H
  157.         dw      offset _TEXT:fxn57h     ; fxn 57H get/set file date
  158.         dw      offset _TEXT:error      ; fxn 58H
  159.         dw      offset _TEXT:abort      ; fxn 59H
  160.         dw      offset _TEXT:fxn5ah     ; fxn 5AH create temp file
  161.         dw      offset _TEXT:fxn5bh     ; fxn 5BH create unique file
  162.         dw      offset _TEXT:fxn5ch     ; fxn 5CH lock/unlock
  163.         dw      offset _TEXT:abort      ; fxn 5DH
  164.         dw      offset _TEXT:error      ; fxn 5EH
  165.         dw      offset _TEXT:error      ; fxn 5FH
  166.         dw      offset _TEXT:abort      ; fxn 60H
  167.         dw      offset _TEXT:abort      ; fxn 61H
  168.         dw      offset _TEXT:abort      ; fxn 62H
  169.         dw      offset _TEXT:error      ; fxn 63H
  170.         dw      offset _TEXT:abort      ; fxn 64H
  171.         dw      offset _TEXT:error      ; fxn 65H
  172.         dw      offset _TEXT:error      ; fxn 66H
  173.         dw      offset _TEXT:error      ; fxn 67H
  174.         dw      offset _TEXT:fxn68h     ; fxn 68H commit file
  175.         dw      offset _TEXT:abort      ; fxn 69H
  176.         dw      offset _TEXT:abort      ; fxn 6AH
  177.         dw      offset _TEXT:abort      ; fxn 6BH
  178.         dw      offset _TEXT:error      ; fxn 6CH
  179.         dw      offset _TEXT:abort      ; fxn 6DH
  180.         dw      offset _TEXT:abort      ; fxn 6EH
  181.         dw      offset _TEXT:abort      ; fxn 6FH
  182.  
  183. _DATA   ends
  184.  
  185. _TEXT   segment byte public 'CODE'
  186.  
  187.         assume  cs:_TEXT,ds:DGROUP
  188. ;
  189. ; Initialization routine for the Tiny DOS Extender.  First we test for
  190. ; the presence of a DPMI host, get the address of the mode switch entry 
  191. ; point, and request the switch to protected mode.  Then we install
  192. ; a handler for GP faults to circumvent the Win 3 brain-damaged dialog
  193. ; box, and allocate some memory below 1 MB to use as a buffer for
  194. ; communication with DOS.  Finally we install our own Int 21H handler 
  195. ; so we can service DOS calls from the protected mode application.
  196. ;
  197.         public  initdosx
  198. initdosx proc   near
  199.  
  200.         mov     ax,1687h                ; get address of DPMI 
  201.         int     2fh                     ;   mode switch entry point
  202.         or      ax,ax                   ; bail out if no DPMI
  203.         jnz     init9
  204.         mov     word ptr modesw,di      ; save far pointer to 
  205.         mov     word ptr modesw+2,es    ;   DPMI entry point
  206.  
  207.         mov     bx,si                   ; allocate DPMI private data
  208.         mov     ah,48h                  ; area below 1 MB boundary
  209.         int     21h
  210.         jc      init9                   ; jump, allocation failed
  211.  
  212.         mov     es,ax                   ; pass segment of data area     
  213.         mov     ax,0                    ; bit 0=0 indicates 16-bit app
  214.         call    modesw                  ; switch to protected mode
  215.  
  216.         mov     ax,0202h                ; get address of previous
  217.         mov     bl,0dh                  ; owner of GP fault vector
  218.         int     31h
  219.         mov     word ptr int0dv,dx      ; save as far pointer
  220.         mov     word ptr int0dv+2,cx
  221.  
  222.         mov     ax,0203h                ; install our GP fault handler
  223.         mov     bl,0dh
  224.         mov     cx,cs                   ; CX:DX = handler address
  225.         mov     dx,offset _TEXT:gpfisr
  226.         int     31h
  227.         jc      init9                   ; jump, couldn't install
  228.  
  229.         mov     ax,0100h                ; allocate 64 KB buffer in
  230.         mov     bx,1000h                ; conventional memory for
  231.         int     31h                     ; communication with DOS
  232.         jc      init9                   ; jump, allocation failed
  233.         mov     realseg,ax              ; save segment of block
  234.         mov     realsel,dx              ; save selector for block
  235.  
  236.         mov     ax,0204h                ; get address of previous
  237.         mov     bl,21h                  ; owner of Int 21H vector
  238.         int     31h
  239.         mov     word ptr int21v,dx      ; save as far pointer
  240.         mov     word ptr int21v+2,cx
  241.  
  242.         mov     ax,0205h                ; install our Int 21H handler
  243.         mov     bl,21h
  244.         mov     cx,cs                   ; CX:DX = handler address
  245.         mov     dx,offset _TEXT:doscall
  246.         int     31h
  247.  
  248.         xor     ax,ax                   ; return in protected mode
  249.         ret                             ; AX = 0 to signal success
  250.  
  251. init9:  mov     ax,-1                   ; return with AX <> 0 to
  252.         ret                             ; signal initialization failure 
  253.  
  254. initdosx endp
  255. ;
  256. ; Interrupt service routine for GP faults. Entered by a far call 
  257. ; from DPMI host with CS:IP, flags, CPU error code on stack.
  258. ; We force transfer to our error message routine by changing
  259. ; return address in the stack frame.
  260. ;
  261. gpfisr  proc    far
  262.  
  263.         push    bp                      ; point CS:IP in stack frame to
  264.         mov     bp,sp                   ; GP fault error message routine
  265.         mov     word ptr [bp+8],offset _TEXT:gpferr
  266.         pop     bp
  267.         ret
  268.  
  269. gpfisr  endp
  270. ;
  271. ; This routine gains control after the GPFISR returns to the DPMI host.
  272. ; It simply displays an error message and terminates cleanly, subverting
  273. ; Win 3's "Application has violated system integrity" dialog box.
  274. ;
  275. gpferr  proc    near
  276.  
  277.         mov     dx,offset DGROUP:gpfmsg ; display GP fault message
  278.         mov     cx,gpfmsg_len           ; on standard output
  279.         mov     bx,stdout
  280.         mov     ah,40h
  281.         int     21h
  282.         mov     ax,4c01h                ; and terminate with
  283.         int     21h                     ; nonzero return code
  284.  
  285. gpferr  endp
  286. ;
  287. ; The DOSCALL routine is the runtime portion of the Tiny DOS Extender.
  288. ; It traps Int 21H requests in protected mode and performs any necessary
  289. ; mode switching, data movement, and address translation on a 
  290. ; function-by-function basis.  Anything DOSCALL doesn't want to handle,
  291. ; it either fails by setting the Carry flag and returning, or 
  292. ; it aborts the current program.  In particular, all FCB-related 
  293. ; functions are aborted.  When a termination function is detected, 
  294. ; the interrupt handlers are unhooked and the function call is 
  295. ; passed down to the DPMI host so that all other protected mode 
  296. ; resources will be deallocated.
  297. ;
  298. doscall proc    far
  299.  
  300.         push    bx                      ; save register BX
  301.         mov     bl,ah                   ; function number * 2
  302.         xor     bh,bh
  303.         cmp     bx,6fh                  ; function no. too big?
  304.         ja      abort                   ; yes, bail out
  305.         add     bx,bx                   ; no, branch through table
  306.         jmp     [dispatch+bx]           ; to function handler
  307.  
  308. abort:                                  ; unsupported DOS function
  309.         mov     dx,offset DGROUP:abmsg  ; display error message
  310.         mov     cx,abmsg_len
  311.         mov     bx,stdout
  312.         mov     ah,40h
  313.         int     21h                     
  314.         mov     ax,4c01h                ; and exit to DOS
  315.         int     21h
  316.  
  317. error:                                  ; unsupported DOS function
  318.         push    bp                      ; set Carry flag in stack
  319.         mov     bp,sp                   ;   frame to indicate
  320.         or      word ptr [bp+6],1       ;   function failed
  321.         pop     bp                      ; load AX = error code for
  322.         mov     ax,1                    ;   "invalid function number"
  323.         iret                            ; return to application
  324.  
  325.                                         ; common handling for entirely
  326.                                         ;   register-based functions
  327. fxn01h:                                 ; function 01H: char input+echo
  328. fxn02h:                                 ; function 02H: char output
  329. fxn03h:                                 ; function 03H: aux input
  330. fxn04h:                                 ; function 04H: aux output
  331. fxn05h:                                 ; function 05H: printer output
  332. fxn06h:                                 ; function 06H: raw console I/O
  333. fxn07h:                                 ; function 07H: raw input no echo
  334. fxn08h:                                 ; function 08H: char input no echo
  335. fxn0bh:                                 ; function 0BH: input status
  336. fxn0dh:                                 ; function 0DH: disk reset
  337. fxn0eh:                                 ; function 0EH: select disk
  338. fxn19h:                                 ; function 19H: get current drive
  339. fxn1bh:                                 ; function 1BH: get cur. drive data
  340. fxn1ch:                                 ; function 1CH: get drive data
  341. fxn2ah:                                 ; function 2AH: get date
  342. fxn2bh:                                 ; function 2BH: set date
  343. fxn2ch:                                 ; function 2CH: get time
  344. fxn2dh:                                 ; function 2DH: set time
  345. fxn2eh:                                 ; function 2EH: set verify flag
  346. fxn30h:                                 ; function 30H: get DOS version
  347. fxn33h:                                 ; function 33H: get/set break flag
  348. fxn36h:                                 ; function 36H: get drive info
  349. fxn3eh:                                 ; function 3EH: close file
  350. fxn42h:                                 ; function 42H: seek
  351. fxn45h:                                 ; function 45H: dup handle
  352. fxn46h:                                 ; function 46H: redirect handle
  353. fxn54h:                                 ; function 54H: get verify flag
  354. fxn57h:                                 ; function 57H: get/set filedate
  355. fxn5ch:                                 ; function 5CH: lock/unlock
  356. fxn68h:                                 ; function 68H: commit file
  357.         pop     bx                      ; restore BX
  358.         call    saveregs                ; unload general registers
  359.         call    realdos                 ; transfer to DOS
  360.         call    loadregs                ; load general registers & flags
  361.         iret                            ; return to application
  362.  
  363.                                         ; common handling for functions 
  364.                                         ;   passing ASCIIZ addr in DS:DX
  365. fxn39h:                                 ; function 39H: create directory
  366. fxn3ah:                                 ; function 3AH: delete directory
  367. fxn3bh:                                 ; function 3BH: select directory
  368. fxn3ch:                                 ; function 3CH: create file
  369. fxn3dh:                                 ; function 3DH: open
  370. fxn41h:                                 ; function 41H: delete file
  371. fxn43h:                                 ; function 43H: get/set attributes
  372. fxn5ah:                                 ; function 5AH: create temp file
  373. fxn5bh:                                 ; function 5BH: create unique file
  374.         pop     bx                      ; restore BX
  375.         call    saveregs                ; unload general registers
  376.         mov     es,realsel              ; ES:DI = virtual address of
  377.         xor     di,di                   ;         real mode buffer
  378.         mov     si,dx                   ; DS:SI = virtual address of
  379.         cld                             ;         protected mode buffer
  380. @@1:    lodsb                           ; copy ASCIIZ string to 
  381.         stosb                           ; real mode buffer
  382.         or      al,al                   ; reached null yet?
  383.         jnz     @@1                     ; no, copy another character
  384.         mov     ax,realseg              ; set address of real mode buffer
  385.         mov     regDS,ax                ; into register data structure
  386.         mov     regDX,0
  387.         call    realdos                 ; transfer to MS-DOS
  388.         call    loadregs                ; load general registers & flags
  389.         mov     dx,protDX               ; restore protected mode DX, ES
  390.         mov     es,protES
  391.         iret                            ; return to application
  392.  
  393. fxn3fh:                                 ; function 3FH: read file
  394.         pop     bx                      ; restore BX
  395.         call    saveregs                ; unload general registers
  396.         mov     ax,realseg              ; set address of real mode buffer
  397.         mov     regDS,ax                ; into register data structure
  398.         mov     regDX,0
  399.         call    realdos                 ; transfer to MS-DOS
  400.         mov     cx,regCX                ; CX = actual length of data 
  401.         push    ds                      ; ES:DI = virtual address of
  402.         pop     es                      ;         protected mode buffer
  403.         mov     di,protDX
  404.         mov     ds,realsel              ; DS:SI = virtual address of
  405.         xor     si,si                   ;         real mode buffer
  406.         cld                             ; copy data from real mode
  407.         rep movsb                       ; buffer to protected mode buffer
  408.         push    es                      ; restore DS = our DGROUP
  409.         pop     ds
  410.         call    loadregs                ; load general registers
  411.         mov     dx,protDX               ; restore protected mode DX, ES 
  412.         mov     es,protES
  413.         iret                            ; return to application
  414.  
  415. fxn40h:                                 ; function 40H: write file
  416.         pop     bx                      ; restore BX
  417.         call    saveregs                ; unload general registers
  418.         mov     es,realsel              ; ES:DI = virtual address of
  419.         xor     di,di                   ;         real mode buffer
  420.         mov     si,dx                   ; DS:SI = virtual address of
  421.         cld                             ;         protected mode buffer
  422.         rep movsb                       ; copy data to real mode buffer
  423.         mov     ax,realseg              ; set address of real mode buffer
  424.         mov     regDS,ax                ; into register data structure
  425.         mov     regDX,0
  426.         call    realdos                 ; transfer to MS-DOS
  427.         call    loadregs                ; load general registers & flags
  428.         mov     dx,protDX               ; restore protected mode DX, ES
  429.         mov     es,protES
  430.         iret                            ; return to application
  431.  
  432. fxn47h:                                 ; function 47H: get directory
  433.         pop     bx                      ; restore BX
  434.         call    saveregs                ; unload general registers
  435.         mov     ax,realseg              ; set address of real mode buffer
  436.         mov     regDS,ax                ; into register data structure
  437.         mov     regSI,0
  438.         call    realdos                 ; transfer to MS-DOS
  439.         push    ds                      ; ES:DI = virtual address of
  440.         pop     es                      ;         protected mode buffer
  441.         mov     di,protSI
  442.         mov     ds,realsel              ; DS:SI = virtual address of
  443.         xor     si,si                   ;         real mode buffer
  444.         cld                             
  445. @@2:    lodsb                           ; copy ASCIIZ string from real
  446.         stosb                           ; mode buffer to prot mode buffer
  447.         or      al,al                   ; found null character yet?
  448.         jnz     @@2                     ; no, copy another character
  449.         push    es                      ; restore DS = our DGROUP
  450.         pop     ds
  451.         call    loadregs                ; load general registers
  452.         mov     si,protSI               ; restore protected mode SI, ES 
  453.         mov     es,protES
  454.         iret                            ; return to application
  455.  
  456. fxn00h:                                 ; function 00H: terminate
  457. fxn4ch: pop     bx                      ; function 4CH: terminate
  458.         push    ax                      ; save return code
  459.         mov     ax,0203h                ; restore old GP fault handler
  460.         mov     bl,0dh
  461.         mov     cx,word ptr int0dv+2
  462.         mov     dx,word ptr int0dv  
  463.         int     31h
  464.         mov     ax,0205h                ; restore old Int 21H handler
  465.         mov     bl,21h
  466.         mov     cx,word ptr int21v+2
  467.         mov     dx,word ptr int21v  
  468.         int     31h
  469.         mov     ax,0101h                ; release real mode buffer      
  470.         mov     dx,realsel
  471.         int     31h
  472.         pop     ax                      ; chain to DPMI Int 21H handler 
  473.         int     21h                     ; for cleanup and termination
  474.  
  475. chain:                                  ; general fallthrough point
  476.                                         ; (useful during debugging)
  477.         pop     bx                      ; restore register BX
  478.         jmp     int21v                  ; chain to prev Int 21H owner
  479.  
  480. doscall endp
  481. ;
  482. ; Save general registers into real mode data structure for a call to
  483. ; real mode routine via DPMI translation services.  Note that segment
  484. ; registers are NOT unloaded into structure because they are not valid
  485. ; for real mode anyway.
  486. ;
  487. saveregs proc   near
  488.  
  489.         mov     regAX,ax                ; save general registers
  490.         mov     regBX,bx
  491.         mov     regCX,cx
  492.         mov     regDX,dx
  493.         mov     regSI,si
  494.         mov     regDI,di
  495.         mov     regBP,bp
  496.         mov     protDX,dx               ; extra copies for non-
  497.         mov     protSI,si               ; register-based functions
  498.         mov     protES,es
  499.         ret
  500.  
  501. saveregs endp
  502. ;
  503. ; Load general registers from real mode data structure.  Note that 
  504. ; segment registers are NOT loaded because their real mode values 
  505. ; would cause a GP fault in protected mode.
  506. ;
  507. loadregs proc   near
  508.  
  509.         mov     bp,sp                   ; update CPU flags in
  510.         push    cpuFLAGS                ; stack frame to return
  511.         pop     [bp+6]                  ; DOS function status
  512.         mov     ax,regAX                ; load general registers        
  513.         mov     bx,regBX
  514.         mov     cx,regCX
  515.         mov     dx,regDX
  516.         mov     si,regSI
  517.         mov     di,regDI
  518.         mov     bp,regBP
  519.         ret
  520.  
  521. loadregs endp
  522. ;
  523. ; Call the DPMI translation function 0300H to simulate a real mode 
  524. ; software interrupt 21H, transferring control to MS-DOS, passing 
  525. ; the values stored into the real mode register structure 'regs'.
  526. ;
  527. realdos proc    near
  528.  
  529.         push    es
  530.         mov     ax,0300h                ; DPMI Function 0300H 
  531.         mov     bl,21h                  ; software interrupt 21H
  532.         mov     bh,0                    ; flags (bit 0 must be 0)
  533.         mov     cx,0                    ; no. of stack words to copy
  534.         push    ds                      ; ES:DI = address of real
  535.         pop     es                      ; mode register structure
  536.         mov     di,offset DGROUP:regs
  537.         int     31h                     ; to DOS via DPMI host
  538.         pop     es
  539.         ret
  540.  
  541. realdos endp
  542.  
  543. _TEXT   ends
  544.  
  545.         end
  546.